﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once
#include "NdbObjectMemoryModelNode.h"
#include "NdbObjectMemoryModelLeafNode.h"
#include "NdbObjectMemoryModelGroupNode.h"
#include "NdbObjectMemoryModelFixedLengthNodes.h"
#include "RawMemory.h"
#include "GbmpCommon.h"
#include <algorithm>
#include <string>
#include <sstream>
#include "GbmpAssert.h"

namespace gcmp
{
    template <typename T>
    struct NdbObjectMemoryModelPropertyAccessor
    {
        //////////////////////////////////////////////////////////////////////////
        /*
        *@brief     获取叶子节点的属性数据
        */
        static const T * GetProperty(const NdbObjectMemoryModelLeafNode * pLeafNode, bool & res)
        {
            if (nullptr == pLeafNode)
            {
                return nullptr;
            }
            const RawMemory& opRawMemory = pLeafNode->GetRawMemory();
            if (opRawMemory.IsValid())
            {
                res = true;
                return reinterpret_cast<const T*>(opRawMemory.GetStartAddress());
            }
            else
            {
                res = false;
                return nullptr;
            }
        }

        static const T * GetProperty(const NdbObjectMemoryModelFixedLengthNode * pNode, bool & res)
        {
            if (nullptr == pNode)
            {
                return nullptr;
            }
            if (const void * pData = pNode->GetData())
            {
                res = true;
                return reinterpret_cast<const T*>(pData);
            }
            res = false;
            return nullptr;
        }

        /*
        *@brief     按名字判断对象是否含义某属性
        *@return    返回false，如果：
        1)不存在属性
        2)属性的数据类型不是叶子节点(基本类型+ElementID+指针+WString，详见NdbPropertySchemaType.h)
        *@note      如果需要获取父对象或派生对象的属性，请在父对象和派生对象里调用该方法
        */
        static bool HasProperty(const NdbObjectMemoryModelGroupNode * pObjectMemoryModelGroupNode, const std::wstring& name)
        {
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pObjectMemoryModelGroupNode, L"pObjectMemoryModelGroupNode不应为空", L"GMEP", L"2017/06/07");

            const std::vector<OwnerPtr<NdbObjectMemoryModelNode>>& childNodes = pObjectMemoryModelGroupNode->GetSubNodes();
            auto ite = std::find_if(childNodes.begin(), childNodes.end(), [&name](const OwnerPtr<NdbObjectMemoryModelNode>& opNode) -> bool {
                return (opNode->GetName() == name);
            });

            return ite != childNodes.end() && (*ite)->IsLeaf();
        }

        /*
        *@brief     按名字获取对象的属性数据
        *@return    返回false，如果：
        1)不存在属性
        2)属性的数据类型不是叶子节点(基本类型+ElementID+指针+WString，详见NdbPropertySchemaType.h)
        *@note      如果需要获取父对象或派生对象的属性，请在父对象和派生对象里调用该方法
        */
        static const T * GetProperty(const NdbObjectMemoryModelGroupNode * pObjectMemoryModelGroupNode, const std::wstring& name, bool & res)
        {
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pObjectMemoryModelGroupNode, L"pObjectMemoryModelGroupNode不应为空", L"GMEP", L"2017/06/07");

            const std::vector<OwnerPtr<NdbObjectMemoryModelNode>>& childNodes = pObjectMemoryModelGroupNode->GetSubNodes();
            auto ite = std::find_if(childNodes.begin(), childNodes.end(), [&name](const OwnerPtr<NdbObjectMemoryModelNode>& opNode) -> bool {
                return (opNode->GetName() == name);
            });

            if (ite == childNodes.end())
            {
                std::wostringstream woss;
                woss << L"没有找到对象的属性:" << name;
                DBG_WARN(woss.str(), L"GMEP", L"2017/01/22");
                res = false;
                return nullptr;
            }

            if (!(*ite)->IsLeaf())
            {
                std::wostringstream woss;
                woss << L"属性:" << name << L"的数据类型是复合类型（非叶子节点）,不建议直接取用。请参见NdbPropertySchemaType.h中属性数据类型的定义";
                DBG_WARN(woss.str(), L"GMEP", L"2017/01/22");
                res = false;
                return nullptr;
            }
            const NdbObjectMemoryModelNode * pChildNode = (*ite).get();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pChildNode, L"找到的属性节点为空？", L"GMEP", L"2022/01/05");
            NdbObjectMemoryModelNodeType childNodeType = pChildNode->GetType();
            if (NdbObjectMemoryModelNodeType::Fixed8Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::Fixed16Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::Fixed32Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::Fixed64Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::FixedDouble == childNodeType || 
                NdbObjectMemoryModelNodeType::FixedFloat == childNodeType)
            {
                const NdbObjectMemoryModelFixedLengthNode* pFixedLengthNode = thread_safe_quick_cast<NdbObjectMemoryModelFixedLengthNode>((*ite).get());
                DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFixedLengthNode, L"节点声明的类型和实际类型不一致", L"GMEP", L"2022/01/05");
                return NdbObjectMemoryModelPropertyAccessor<T>::GetProperty(pFixedLengthNode, res);
            }
            else
            {
                const NdbObjectMemoryModelLeafNode* pLeafNode = thread_safe_quick_cast<NdbObjectMemoryModelLeafNode>((*ite).get());
                DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLeafNode, L"Only support set property of leaf node", L"GMEP", L"2020/10/31");
                return NdbObjectMemoryModelPropertyAccessor<T>::GetProperty(pLeafNode, res);
            }
        }

        /*
        *@brief     设置叶子节点的属性数据
        */
        static bool SetProperty(NdbObjectMemoryModelLeafNode *pLeafNode, const T& val)
        {
            GBMP_ASSERT(pLeafNode);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pLeafNode, L"Only support set property of leaf node", L"GMEP", L"2020/10/31");
            RawMemory& opRawMemory = pLeafNode->GetDataFW();
            opRawMemory.Resize(sizeof(T));
            return (nullptr != opRawMemory.ConstructObject<T>(val));
        }

        /// \brief 设置固定长度节点的属性数据
        static bool SetProperty(NdbObjectMemoryModelFixedLengthNode* pNode, const T& value)
        {
            if (nullptr == pNode) return false;
            void * pData = pNode->GetDataForWrite();
            if (nullptr == pData) return false;
            *(reinterpret_cast<T*>(pData)) = value;
            return true;
        }

        /*
        *@brief     按名字设置对象的属性数据，类型T必须是基本类型+ElementID+指针+WString，详见NdbPropertySchemaType.h
        *@return    返回false，如果：
        1)存在该属性但属性类型不符合要求
        2)设置失败
        *@note      如果需要设置父对象或派生对象的属性，请在父对象和派生对象里调用该方法
        */
        /*template <typename T>*/
        static bool SetProperty(NdbObjectMemoryModelGroupNode * pObjectMemoryModelGroupNode, const std::wstring& name, const T& val)
        {
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pObjectMemoryModelGroupNode, L"pObjectMemoryModelGroupNode不应为空", L"GMEP", L"2017/06/07");

            std::vector<OwnerPtr<NdbObjectMemoryModelNode>>& childNodes = pObjectMemoryModelGroupNode->GetSubNodesFW();
            auto ite = std::find_if(childNodes.begin(), childNodes.end(), [&name](const OwnerPtr<NdbObjectMemoryModelNode>& opNode) -> bool {
                if (!opNode->IsLeaf())
                {
                    return false;
                }
                const NdbObjectMemoryModelLeafNode * pLeafNode = thread_safe_quick_cast<NdbObjectMemoryModelLeafNode>(opNode.get());
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pLeafNode, L"只支持LeftNode", L"GMEP", L"2020/10/31");
                return (pLeafNode->GetName() == name);
            });

            if (ite == childNodes.end())
            {
                return false;
            }

            NdbObjectMemoryModelNode * pChildNode = (*ite).get();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pChildNode, L"找到的属性节点为空？", L"GMEP", L"2022/01/05");
            NdbObjectMemoryModelNodeType childNodeType = pChildNode->GetType();
            if (NdbObjectMemoryModelNodeType::Fixed8Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::Fixed16Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::Fixed32Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::Fixed64Bits == childNodeType ||
                NdbObjectMemoryModelNodeType::FixedDouble == childNodeType ||
                NdbObjectMemoryModelNodeType::FixedFloat == childNodeType)
            {
                const NdbObjectMemoryModelFixedLengthNode* pFixedLengthNode = thread_safe_quick_cast<NdbObjectMemoryModelFixedLengthNode>((*ite).get());
                DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLeafNode, L"节点声明的类型和实际类型不一致", L"GMEP", L"2022/01/05");
                return NdbObjectMemoryModelPropertyAccessor<T>::SetProperty(pFixedLengthNode, res);
            }
            else
            {
                NdbObjectMemoryModelLeafNode * pLeafNode = thread_safe_quick_cast<NdbObjectMemoryModelLeafNode>((*ite).get());
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pLeafNode, L"Only support set property of leaf node", L"GMEP", L"2020/10/31");
                return NdbObjectMemoryModelPropertyAccessor<T>::SetProperty(pLeafNode, val);
            }
        }
    };
}
 